home *** CD-ROM | disk | FTP | other *** search
- /* main.c -
- Main program for sgmls.
-
- Written by James Clark (jjc@jclark.com).
- */
-
- #include "config.h"
- #include "std.h"
- #include "getopt.h"
- #include "entity.h" /* Templates for entity control blocks. */
- #include "adl.h" /* Definitions for attribute list processing. */
- #include "sgmlmain.h" /* Main interface to SGML services. */
- #include "appl.h"
-
- #define READCNT 512
-
- /* Before using argv[0] in error messages, strip off everything up to and
- including the last character in prog that occurs in PROG_PREFIX. */
-
- #ifndef PROG_PREFIX
- #define PROG_PREFIX "/"
- #endif /* not PROG_PREFIX */
-
- /* Message catalogue name. */
- #define CAT_NAME "sgmls"
- /* Message set to use for application error messages. */
- #define APP_SET 4
-
- #ifdef HAVE_EXTENDED_PRINTF
- #define xvfprintf vfprintf
- #else
- extern int xvfprintf P((FILE *, char *, va_list));
- #endif
-
- static VOID usage P((void));
- static VOID fatal VP((int, ...));
- static VOID do_error P((int, va_list));
- static VOID swinit P((struct switches *));
- static VOID write_caps P((char *, struct sgmlcap *));
-
- static UNIV make_docent P((int, char **));
- static char *munge_program_name P((char *, char *));
- static VOID die P((void));
- #ifdef SUPPORT_SUBDOC
- static VOID build_subargv P((struct switches *));
- static VOID cleanup P((void));
- static char *create_subcap_file P((void));
- #endif /* SUPPORT_SUBDOC */
-
- static char *errlist[] = {
- 0,
- "Out of memory",
- "Cannot open SGML document entity",
- "Cannot exec `%s': %s",
- "Cannot fork: %s",
- "Error waiting for process: %s",
- "Program %s got fatal signal %d",
- "Cannot open `%s': %s",
- "Subdocument capacity botch",
- "Non-existent subdocument entity `%s' not processed",
- };
-
- int suppsw = 0; /* Non-zero means suppress output. */
- int locsw = 0; /* Non-zero means generate location info. */
- static char *prog; /* Program name (for error messages). */
- static nl_catd catd; /* Message catalogue descriptor. */
- static char *capfile = 0; /* File for capacity report. */
- extern char *version_string;
-
- char options[] = {
- 'c', ':', 'd', 'e', 'g', 'i', ':', 'l', 'o', ':', 'p', 'r', 's', 'u', 'v',
- #ifdef CANT_REDIRECT_STDERR
- 'f', ':',
- #endif /* CANT_REDIRECT_STDERR */
- #ifdef TRACE
- 'x', ':', 'y', ':',
- #endif /* TRACE */
- '\0'
- };
-
- #ifdef SUPPORT_SUBDOC
- int suberr = 0; /* Error in subdocument. */
- static char *subargv[sizeof(options)];
- static int subargc = 0;
- static char nopenbuf[sizeof(long)*3 + 1];
- static char sgmldecl_file[L_tmpnam];
- static char subcap_file[L_tmpnam];
- #endif
-
- int main(argc, argv)
- int argc;
- char **argv;
- {
- static char stderr_buf[BUFSIZ];
- int opt;
- #ifdef CANT_REDIRECT_STDERR
- char *errfile = 0;
- #endif
- struct sgmlcap cap;
- struct switches sw;
- int nincludes = 0; /* number of -i options */
- setbuf(stderr, stderr_buf);
-
- /* Define MAIN_HOOK in config.h if some function needs to be called here. */
- #ifdef MAIN_HOOK
- MAIN_HOOK(argc, argv);
- #endif
- #ifdef SUPPORT_SUBDOC
- subargv[subargc++] = argv[0];
- #endif
-
- prog = argv[0] = munge_program_name(argv[0], "sgmls");
-
- catd = catopen(CAT_NAME, 0);
- swinit(&sw);
-
- while ((opt = getopt(argc, argv, options)) != EOF) {
- switch (opt) {
- case 'l': /* Generate location information. */
- locsw = 1;
- break;
- case 'c': /* Print capacity usage. */
- capfile = optarg;
- break;
- case 's': /* Suppress output. */
- suppsw = 1;
- break;
- case 'd': /* Report duplicate entity declarations. */
- sw.swdupent = 1;
- break;
- case 'e': /* Provide entity stack trace in error msg. */
- sw.swenttr = 1;
- break;
- #ifdef CANT_REDIRECT_STDERR
- case 'f': /* Redirect errors. */
- errfile = optarg;
- break;
- #endif /* CANT_REDIRECT_STDERR */
- case 'g': /* Provide GI stack trace in error messages. */
- sw.sweltr = 1;
- break;
- case 'p': /* Parse only the prolog. */
- sw.onlypro = 1;
- suppsw = 1;
- break;
- case 'r': /* Give warning for defaulted references. */
- sw.swrefmsg = 1;
- break;
- case 'u':
- sw.swundef = 1;
- break;
- #ifdef TRACE
- case 'x': /* Trace options for the document body. */
- sw.trace = optarg;
- break;
- case 'y': /* Trace options for the prolog. */
- sw.ptrace = optarg;
- break;
- #endif /* TRACE */
- case 'v': /* Print the version number. */
- fprintf(stderr, "sgmls version %s\n", version_string);
- fflush(stderr);
- break;
- case 'o':
- sw.nopen = atol(optarg);
- if (sw.nopen <= 0)
- usage();
- break;
- case 'i': /* Define parameter entity as "INCLUDE". */
- sw.includes = (char **)xrealloc((UNIV)sw.includes,
- (nincludes + 2)*sizeof(char *));
- sw.includes[nincludes++] = optarg;
- sw.includes[nincludes] = 0;
- break;
- case '?':
- usage();
- default:
- abort();
- }
- }
-
- #ifdef CANT_REDIRECT_STDERR
- if (errfile) {
- FILE *fp;
- errno = 0;
- fp = fopen(errfile, "w");
- if (!fp)
- fatal(E_OPEN, errfile, strerror(errno));
- fclose(fp);
- errno = 0;
- if (!freopen(errfile, "w", stderr)) {
- /* Can't use fatal() since stderr is now closed */
- printf("%s: ", prog);
- printf(errlist[E_OPEN], errfile, strerror(errno));
- putchar('\n');
- exit(EXIT_FAILURE);
- }
- }
- #endif /* CANT_REDIRECT_STDERR */
-
- (void)sgmlset(&sw);
-
- #ifdef SUPPORT_SUBDOC
- build_subargv(&sw);
- #endif
- if (sgmlsdoc(make_docent(argc - optind, argv + optind)))
- fatal(E_DOC);
-
- process_document(sw.nopen > 0);
- sgmlend(&cap);
- if (capfile)
- write_caps(capfile, &cap);
- #ifdef SUPPORT_SUBDOC
- cleanup();
- if (suberr)
- exit(EXIT_FAILURE);
- #endif /* SUPPORT_SUBDOC */
- if (sgmlgcnterr() > 0)
- exit(EXIT_FAILURE);
- if (!sw.nopen)
- output_conforming();
- exit(EXIT_SUCCESS);
- }
-
- static char *munge_program_name(arg, dflt)
- char *arg, *dflt;
- {
- char *p;
- #ifdef PROG_STRIP_EXTENSION
- char *ext;
- #endif
- if (!arg || !*arg)
- return dflt;
- p = strchr(arg, '\0');
- for (;;) {
- if (p == arg)
- break;
- --p;
- if (strchr(PROG_PREFIX, *p)) {
- p++;
- break;
- }
- }
- arg = p;
- #ifdef PROG_STRIP_EXTENSION
- ext = strrchr(arg, '.');
- if (ext) {
- p = (char *)xmalloc(ext - arg + 1);
- memcpy(p, arg, ext - arg);
- p[ext - arg] = '\0';
- arg = p;
- }
- #endif /* PROG_STRIP_EXTENSION */
- #ifdef PROG_FOLD
- #ifdef PROG_STRIP_EXTENSION
- if (!ext) {
- #endif
- p = xmalloc(strlen(arg) + 1);
- strcpy(p, arg);
- arg = p;
- #ifdef PROG_STRIP_EXTENSION
- }
- #endif
- for (p = arg; *p; p++)
- if (ISASCII((unsigned char)*p) && isupper((unsigned char)*p))
- *p = tolower((unsigned char)*p);
- #endif /* PROG_FOLD */
- return arg;
- }
-
- static UNIV make_docent(argc, argv)
- int argc;
- char **argv;
- {
- UNS len = 1;
- int i;
- UNIV res;
- char *ptr;
- static char *stdinname = STDINNAME;
-
- if (argc == 0) {
- argv = &stdinname;
- argc = 1;
- }
-
- for (i = 0; i < argc; i++)
- len += strlen(argv[i]) + 1;
-
- res = xmalloc(len);
- ptr = (char *)res;
- for (i = 0; i < argc; i++) {
- strcpy(ptr, argv[i]);
- ptr = strchr(ptr, '\0') + 1;
- }
- *ptr = '\0';
- return res;
- }
-
-
- static VOID usage()
- {
- /* Don't mention -o since this are for internal use only. */
- fprintf(stderr, "Usage: %s [-deglprsuv]%s [-c file] [-i entity]%s [filename ...]\n",
- prog,
- #ifdef CANT_REDIRECT_STDERR
- " [-f file]",
- #else /* not CANT_REDIRECT_STDERR */
- "",
- #endif /* not CANT_REDIRECT_STDERR */
- #ifdef TRACE
- " [-x flags] [-y flags]"
- #else /* not TRACE */
- ""
- #endif /* not TRACE */
- );
- exit(EXIT_FAILURE);
- }
-
- static VOID die()
- {
- #ifdef SUPPORT_SUBDOC
- cleanup();
- #endif /* SUPPORT_SUBDOC */
- exit(EXIT_FAILURE);
- }
-
- static VOID swinit(swp)
- struct switches *swp;
- {
- swp->swenttr = 0;
- swp->sweltr = 0;
- swp->swbufsz = READCNT+2;
- swp->prog = prog;
- swp->swdupent = 0;
- swp->swrefmsg = 0;
- #ifdef TRACE
- swp->trace = 0;
- swp->ptrace = 0;
- #endif /* TRACE */
- swp->catd = catd;
- swp->swambig = 1; /* Always check for ambiguity. */
- swp->swundef = 0;
- swp->nopen = 0;
- swp->onlypro = 0;
- swp->includes = 0;
- swp->die = die;
- }
-
- #ifdef SUPPORT_SUBDOC
-
- static VOID build_subargv(swp)
- struct switches *swp;
- {
- if (suppsw)
- subargv[subargc++] = "-s";
- if (locsw)
- subargv[subargc++] = "-l";
- if (swp->swdupent)
- subargv[subargc++] = "-d";
- if (swp->swenttr)
- subargv[subargc++] = "-e";
- if (swp->sweltr)
- subargv[subargc++] = "-g";
- if (swp->swrefmsg)
- subargv[subargc++] = "-r";
- #ifdef TRACE
- if (swp->trace) {
- subargv[subargc++] = "-x";
- subargv[subargc++] = swp->trace;
- }
- if (swp->ptrace) {
- subargv[subargc++] = "-y";
- subargv[subargc++] = swp->ptrace;
- }
- #endif /* TRACE */
- subargv[subargc++] = "-o";
- sprintf(nopenbuf, "%ld", swp->nopen + 1);
- subargv[subargc++] = nopenbuf;
- }
-
-
- static
- VOID handler(sig)
- int sig;
- {
- signal(sig, SIG_DFL);
- cleanup();
- raise(sig);
- }
-
- static
- VOID cleanup()
- {
- if (sgmldecl_file[0]) {
- (void)remove(sgmldecl_file);
- sgmldecl_file[0] = '\0';
- }
- if (subcap_file[0]) {
- (void)remove(subcap_file);
- subcap_file[0] = '\0';
- }
- }
-
- static
- char *store_sgmldecl()
- {
- if (!sgmldecl_file[0]) {
- FILE *fp;
- if (signal(SIGINT, SIG_IGN) != SIG_IGN)
- signal(SIGINT, handler);
- #ifdef SIGTERM
- if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
- signal(SIGTERM, handler);
- #endif /* SIGTERM */
- #ifdef SIGPIPE
- if (signal(SIGPIPE, SIG_IGN) != SIG_IGN)
- signal(SIGPIPE, handler);
- #endif
- #ifdef SIGHUP
- if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
- signal(SIGHUP, handler);
- #endif
- tmpnam(sgmldecl_file);
- errno = 0;
- fp = fopen(sgmldecl_file, "w");
- if (!fp)
- fatal(E_OPEN, sgmldecl_file, strerror(errno));
- sgmlwrsd(fp);
- fclose(fp);
- }
- return sgmldecl_file;
- }
-
- static
- char *create_subcap_file()
- {
- if (subcap_file[0] == '\0') {
- FILE *fp;
- tmpnam(subcap_file);
- fp = fopen(subcap_file, "w");
- if (!fp)
- fatal(E_OPEN, subcap_file, strerror(errno));
- fclose(fp);
- }
- return subcap_file;
- }
-
- char **make_argv(id)
- UNIV id;
- {
- int nfiles;
- char *p;
- char **argv;
- int i;
-
- for (p = (char *)id, nfiles = 0; *p; p = strchr(p, '\0') + 1)
- nfiles++;
-
- argv = (char **)xmalloc((subargc + 2 + 1 + nfiles + 1)*sizeof(char *));
- memcpy((UNIV)argv, (UNIV)subargv, subargc*sizeof(char *));
-
- i = subargc;
-
- argv[i++] = "-c";
- argv[i++] = create_subcap_file();
-
- argv[i++] = store_sgmldecl();
-
- for (p = (char *)id; *p; p = strchr(p, '\0') + 1)
- argv[i++] = p;
- argv[i] = 0;
- return argv;
- }
-
- VOID get_subcaps()
- {
- long cap[NCAPACITY];
- FILE *fp;
- int i;
-
- if (!subcap_file[0])
- return;
- errno = 0;
- fp = fopen(subcap_file, "r");
- if (!fp)
- fatal(E_OPEN, subcap_file, strerror(errno));
- for (i = 0; i < NCAPACITY; i++)
- if (fscanf(fp, "%*s %ld", cap + i) != 1)
- fatal(E_CAPBOTCH);
- fclose(fp);
- sgmlsubcap(cap);
- }
-
-
- #endif /* SUPPORT_SUBDOC */
-
- /* Print capacity statistics.*/
-
- static VOID write_caps(name, p)
- char *name;
- struct sgmlcap *p;
- {
- FILE *fp;
- int i;
- fp = fopen(name, "w");
- if (!fp)
- fatal(E_OPEN, name, strerror(errno));
- /* This is in RACT format. */
- for (i = 0; i < NCAPACITY; i++)
- fprintf(fp, "%s %ld\n", p->name[i], p->number[i]*p->points[i]);
- fclose(fp);
- }
-
- UNIV xmalloc(n)
- UNS n;
- {
- UNIV p = malloc(n);
- if (!p)
- fatal(E_NOMEM);
- return p;
- }
-
- UNIV xrealloc(s, n)
- UNIV s;
- UNS n;
- {
- s = s ? realloc(s, n) : malloc(n);
- if (!s)
- fatal(E_NOMEM);
- return s;
- }
-
- static
- #ifdef VARARGS
- VOID fatal(va_alist) va_dcl
- #else
- VOID fatal(int errnum,...)
- #endif
- {
- #ifdef VARARGS
- int errnum;
- #endif
- va_list ap;
-
- #ifdef VARARGS
- va_start(ap);
- errnum = va_arg(ap, int);
- #else
- va_start(ap, errnum);
- #endif
- do_error(errnum, ap);
- va_end(ap);
- exit(EXIT_FAILURE);
- }
-
- #ifdef VARARGS
- VOID appl_error(va_alist) va_dcl
- #else
- VOID appl_error(int errnum,...)
- #endif
- {
- #ifdef VARARGS
- int errnum;
- #endif
- va_list ap;
-
- #ifdef VARARGS
- va_start(ap);
- errnum = va_arg(ap, int);
- #else
- va_start(ap, errnum);
- #endif
- do_error(errnum, ap);
- va_end(ap);
- }
-
- static
- VOID do_error(errnum, ap)
- int errnum;
- va_list ap;
- {
- char *text;
- fprintf(stderr, "%s: ", prog);
- assert(errnum > 0);
- assert(errnum < sizeof(errlist)/sizeof(errlist[0]));
- text = catgets(catd, APP_SET, errnum, errlist[errnum]);
- assert(text != 0);
- xvfprintf(stderr, text, ap);
- fputc('\n', stderr);
- fflush(stderr);
- }
-
- /*
- Local Variables:
- c-indent-level: 5
- c-continued-statement-offset: 5
- c-brace-offset: -5
- c-argdecl-indent: 0
- c-label-offset: -5
- comment-column: 30
- End:
- */
-